package lu.uni.adtool.ui;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Frame;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import java.util.EventObject;
import java.util.Set;
import java.util.Vector;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;

import lu.uni.adtool.domains.rings.Bool;
import lu.uni.adtool.domains.rings.BoundedInteger;
import lu.uni.adtool.domains.rings.RealG0;
import lu.uni.adtool.domains.rings.RealZeroOne;
import lu.uni.adtool.domains.rings.Ring;

/**
 * Class showing the map between node names and its valuations.
 * 
 * @author Piot Kordy
 */
public class ValuationView extends JPanel implements KeyListener
{
  static final long serialVersionUID = 94565646654411328L;
  private final String proText = "Proponent";
  private JLabel message;
  private JTable table;
  private JScrollPane scrollPane;
  private ValuationTableModel tableModel;
  /**
   * Constructs a new instance.
   * @param newCanvas associated domain canvas
   */
  public ValuationView()
  {
    super(new BorderLayout());
    message = new JLabel("No attribute domain chosen.");
    tableModel = new ValuationTableModel();
    tableModel.setCanvas(null);
    table = new JTable(tableModel)
    {
      public boolean editCellAt(int row, int column, EventObject e)
      {
    //scrollPane.setVisible(false);
        if(!isCellSelected(row,column)){
          return false;
        };
        String type = (String)getValueAt(row,0);
        String key = (String)getValueAt(row,1);
        boolean editable = false;

        int[] selection = table.getSelectedRows();
        for (int i = 0; (i < selection.length)&&!editable; i++) {
           type = (String)getValueAt(selection[i],0);
           key = (String)getValueAt(selection[i],1);
          if(getCanvas().getDomain().isValueModifiable(type.equals(proText))){
            editable = true;
          }
        }
        if (editable){
          Ring value = editValue(type,key);
          if (value != null){
           selection = table.getSelectedRows();
           for (int i = 0; i < selection.length; i++) {
             type = (String)getValueAt(selection[i],0);
             key = (String)getValueAt(selection[i],1);
             if(getCanvas().getDomain().isValueModifiable(type.equals(proText))){
               getCanvas().putNewValue(type.equals(proText),key,value);
             }
           } 
           getCanvas().valuesUpdated();
          }
        }
        SwingUtilities.invokeLater(new Runnable()
        {
          public void run()
          {
            //table.requestFocusInWindow();
            table.requestFocus();
          }
        });
        return false;
      }
    };
    table.setDefaultRenderer(Ring.class, new ValuationRenderer());
    add(message);
    scrollPane = new JScrollPane(table);
  }

  public Ring editValue(String type, String key)
  {
    Ring value;
    InputDialog dialog;
    if (type.equals(proText)) {
      value = (Ring) getCanvas().getValueAssPro().get(key);
    }
    else {
      value = (Ring) getCanvas().getValueAssOpp().get(key);
    }
    if (value instanceof Bool) {
      value = (Bool) Bool.not((Bool) value);
    }
    else
      if (value instanceof RealG0) {
        dialog = new RealG0Dialog((Frame) getCanvas().getMainWindow());
        value = (RealG0) (dialog.showInputDialog(value));
      }
      else
        if (value instanceof RealZeroOne) {
          dialog = new RealZeroOneDialog(getCanvas().getMainWindow());
          value = (RealZeroOne) (dialog.showInputDialog(value));
        }
        else
          if (value instanceof BoundedInteger) {
            dialog = new BoundedIntegerDialog(getCanvas().getMainWindow());
            value = (BoundedInteger) (dialog.showInputDialog(value));
          }
    return value;
  }
  public void keyPressed(KeyEvent e)
  {
    //System.out.println("Key " + e);
  }

  public void keyReleased(KeyEvent e)
  {
  }

  public void keyTyped(KeyEvent e)
  {
    //System.out.println("Key typed " + e);
  }
  public void assignCanvas(DomainCanvas canvas)
  {
    tableModel.setCanvas(canvas);
    if(canvas!=null){
      remove(message);
      add(scrollPane);
    }
    else{
      remove(scrollPane);
      add(message);
      message.setVisible(true);
    }
    //scrollPane.setVisible(canvas!=null);
  }
  /**
   * Return associated canvas.
   * 
   * @return
   */
  public DomainCanvas getCanvas()
  {
    return tableModel.getCanvas();
  }

  /**
   * Renderer for table cells.
   */
  class ValuationRenderer extends DefaultTableCellRenderer implements TableCellRenderer
  {
    public ValuationRenderer()
    {
      super();
    }
    public Component getTableCellRendererComponent(
                            JTable table, Object value,
                            boolean isSelected, boolean hasFocus,
                            int row, int column) {
      if(value instanceof Ring){
        return super.getTableCellRendererComponent(table,((Ring)value).toUnicode(), isSelected,hasFocus,row,column);
      }
      else{
        return super.getTableCellRendererComponent(table,value, isSelected,hasFocus,row,column);
      }
    }
  }

  class ValuationTableModel extends AbstractTableModel{

    private String[] columnNames = {"Node Type", "Node Label", "Assigned Value"};
    private Vector<Vector> rowData;
    private DomainCanvas canvas;
    /**
     * {@inheritDoc}
     * @see TableModel#getColumnClass(int)
     */
    public Class<?> getColumnClass(int columnIndex)
    {
      if(columnIndex==2) {
        return Ring.class;
      }
      else{
        return getValueAt(0, columnIndex).getClass();
      }
    }

    /**
     * {@inheritDoc}
     * @see TableModel#getColumnName(int)
     */
    public String getColumnName(int col)
    {
      return columnNames[col];
    }

    /**
     * {@inheritDoc}
     * @see TableModel#getRowCount()
     */
    public int getRowCount()
    {
      return rowData.size();
    }

    /**
     * {@inheritDoc}
     * @see TableModel#getValueAt(int,int)
     */
    public Object getValueAt(int row, int col)
    {
      return rowData.elementAt(row).elementAt(col);
    }

    /**
     * {@inheritDoc}
     * @see TableModel#isCellEditable(int,int)
     */
    public boolean isCellEditable(int row, int col)
    {
      if(col>1){
        return true;
      }
      else{
        return false;
      }
    }
    /**
     * {@inheritDoc}
     * 
     * @see TableModel#getColumnCount()
     */
    public int getColumnCount()
    {
      return columnNames.length;
    }

    public void setValueAt(Object value, int row, int col)
    {
      //rowData[row][col] = value;
      fireTableCellUpdated(row, col);
    }

    public void setCanvas(DomainCanvas canvas)
    {
      this.canvas = canvas;
      rowData = getRowData();
      fireTableDataChanged();
    }

    private Vector<Vector> getRowData(){
      if(canvas == null){
        return new Vector();
      }
      Vector<Vector> result = new Vector<Vector>();
      Set<String> keys = canvas.getValueAssPro().keySet();
      for (String key:keys){
        Vector v = new Vector();
        v.add(proText);
        v.add(key);
        v.add(canvas.getValueAssPro().get(key));
        result.add(v);
      }
      keys = canvas.getValueAssOpp().keySet();
      for (String key:keys){
        Vector v = new Vector();
        v.add("Opponent");
        v.add(key);
        v.add(canvas.getValueAssOpp().get(key));
        result.add(v);
      }
      return result;
    }

    /**
     * Gets the canvas for this instance.
     *
     * @return The canvas.
     */
    public DomainCanvas getCanvas()
    {
      return this.canvas;
    }
  }
}
